<?php

declare(strict_types=1);

/**
 * @Author:     Frank
 * @contact     frank_hhm@163.com
 * @Date:       2022-11-05 13:49:48
 * @Last Modified time: 2023-02-13 16:56:13
 */

namespace frank\services;

use think\facade\Cache as CacheStatic;
use think\facade\Config;
use frank\constants\StatusCode;
use frank\exception\CommonException;

use think\facade\Env;

/**
 * 缓存类
 * Class CacheService
 * @package frank\services
 * @mixin \Redis
 */
class CacheService  extends \frank\base\BaseService
{
    /**
     * 标签名
     * @var string
     */
    protected $setCacheName = '_cached_';

    /**
     * 缓存队列key
     * @var string[]
     */
    protected $redisQueueKey = [ ];

    ## 过期时间
    protected $expire;

    ## 获取缓存过期时间
    protected function getExpire(int $expire = null): int
    {
        if ($this->expire) {
            return (int)$this->expire;
        }
        $default = Config::get('cache.default');
        $expire = Config::get('cache.' . $default . '.expire');
        if (!is_int($expire))
            $expire = (int)$expire;

        return $this->expire = $expire;
    }

    ## 写入缓存
    public function set(string $name, $value, int $expire = null): bool
    {
        try {
            return $this->handler()->set($name, $value, $expire ?? $this->getExpire($expire));
        } catch (\Throwable $e) {
            return false;
        }
    }

    ## 如果不存在则写入缓存
    public function get(string $name, $default = false, int $expire = null)
    {
        try {
            return $this->handler()->remember($name, $default, $expire ?? $this->getExpire($expire));
        } catch (\Throwable $e) {
            try {
                if (is_callable($default)) {
                    return $default();
                } else {
                    return $default;
                }
            } catch (\Throwable $e) {
                return null;
            }
        }
    }

    ## 删除缓存
    public function delete(string $name)
    {
        return CacheStatic::delete($name);
    }

    ## 设置句柄
    public function setHandler($tag)
    {
        $this->setCacheName = $tag;
        return $this;
    }

    ## 缓存句柄
    public function handler()
    {
        return CacheStatic::tag($this->setCacheName);
    }

    ## 清空缓存池
    public function clear()
    {
        return $this->handler()->clear();
    }


    ## Redis缓存句柄
    public function redisHandler(string $type = null)
    {
        if ($type) {
            return CacheStatic::store('redis')->tag($type);
        } else {
            return CacheStatic::store('redis');
        }
    }

    ## 放入令牌桶
    public function setTokenBucket(string $key, $value, $expire = null, string $type = 'admin')
    {
        try {
            $redisCahce = $this->redisHandler($type);
            return $redisCahce->set($key, $value, $expire);
        } catch (\Throwable $e) {
            throw new CommonException($e->getMessage());
        }
    }

    ## 清除所有令牌桶
    public function clearTokenAll(string $type = '')
    {
        try {
            return $this->redisHandler($type)->clear();
        } catch (\Throwable $e) {
            throw new CommonException($e->getMessage());
        }
    }

    ## 清除令牌桶
    public function clearToken(string $key)
    {
        try {
            return $this->redisHandler()->delete($key);
        } catch (\Throwable $e) {
            throw new CommonException($e->getMessage());
        }
    }

    ## 查看令牌是否存在
    public function hasToken(string $key)
    {
        return $this->redisHandler()->has($key);
        try {
        } catch (\Throwable $e) {
            throw new CommonException($e->getMessage());
        }
    }

    ## 获取token令牌桶
    public function getTokenBucket(string $key)
    {
        try {
            return $this->redisHandler()->get($key, null);
        } catch (\Throwable $e) {
            throw new CommonException($e->getMessage());
        }
    }

    ## 获取指定分数区间的成员
    public function zRangeByScore($key, $start = '-inf', $end = '+inf', array $options = [])
    {
        return $this->redisHandler()->zRangeByScore($key, $start, $end, $options);
    }

    /**
     * 魔术方法
     * @param $name
     * @param $arguments
     * @return mixed
     */
    public static function __callStatic($name, $arguments)
    {
        return self::redisHandler()->{$name}(...$arguments);
    }

    /**
     * 魔术方法
     * @param $name
     * @param $arguments
     * @return mixed
     */
    public function __call($name, $arguments)
    {
        return $this->redisHandler()->{$name}(...$arguments);
    }

}